home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2010 April / PCWorld0410.iso / pluginy Firefox / 8352 / 8352.xpi / components / gfUpdaterService.js < prev    next >
Text File  |  2009-05-24  |  22KB  |  724 lines

  1. /*
  2.  * Copyright (C) 2008 by Steve Krulewitz <skrulx@gmail.com>
  3.  * Licensed under GPLv2 or later, see file LICENSE in the xpi for details.
  4.  */
  5. const Cc = Components.classes;
  6. const Ci = Components.interfaces;
  7. const Cr = Components.results;
  8. const Cu = Components.utils;
  9.  
  10. const MINUTE_IN_MS = 60 * 1000;
  11.  
  12. const DEBUG = false;
  13.  
  14. const NS_PROFILE_STARTUP_OBSERVER_ID  = "profile-after-change";
  15. const NS_PROFILE_SHUTDOWN_OBSERVER_ID = "profile-before-change";
  16.  
  17. const UPDATE_URL = "http://skrul.com/projects/greasefire/update.php";
  18.  
  19. const JARFILES = ["include.dat", "exclude.dat", "scripts.db", "info.ini"];
  20.  
  21. function TRYIGNORE(aFunc) {
  22.   try {
  23.     aFunc();
  24.   }
  25.   catch (e) {
  26.     Cu.reportError(e);
  27.   }
  28. }
  29.  
  30. function d(s) {
  31.   if (DEBUG) {
  32.     dump("gfUpdaterService: " + s + "\n");
  33.   }
  34. }
  35.  
  36. function gfUpdaterService() {
  37.   d("ctor");
  38.  
  39.   this._gfs = null;
  40.   this._prefs = null;
  41.   this._isUpdating = false;
  42.   this._listeners = [];
  43.  
  44.   this._nextUpdate = null;
  45.   this._timer = null;
  46.   this._wbp = null;
  47.   this._timer;
  48.  
  49.   var obs = Cc["@mozilla.org/observer-service;1"]
  50.               .getService(Ci.nsIObserverService);
  51.   obs.addObserver(this, NS_PROFILE_STARTUP_OBSERVER_ID, false);
  52.   obs.addObserver(this, NS_PROFILE_SHUTDOWN_OBSERVER_ID, false);
  53. }
  54.  
  55. gfUpdaterService.prototype = {
  56.   classDescription: "Greasefire Updater Service",
  57.   classID:          Components.ID("{7c5b9317-0b18-4390-9a0a-a594d544a99f}"),
  58.   contractID:       "@skrul.com/greasefire/updater;1"
  59. }
  60.  
  61. gfUpdaterService.prototype._startup =
  62. function gfUpdaterService__startup()
  63. {
  64.   d("startup");
  65.  
  66.   this._gfs = Cc["@skrul.com/greasefire/service;1"]
  67.                 .getService(Ci.gfIGreasefireService);
  68.  
  69.   this._prefs = Cc["@mozilla.org/preferences-service;1"]
  70.                   .getService(Components.interfaces.nsIPrefService)
  71.                   .getBranch("greasefire.");
  72.  
  73.   // If we are overdue for an update at startup, push it a minute in the future
  74.   // so we don't slow down startup
  75.   if (this.updateIntervalMinutes > 0 && Date.now() > this.nextUpdateDate) {
  76.     this._updateNextUpdateDate(1);
  77.   }
  78.  
  79.   this._timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
  80.   this._timer.initWithCallback(this,
  81.                                MINUTE_IN_MS,
  82.                                Ci.nsITimer.TYPE_REPEATING_SLACK);
  83. }
  84.  
  85. gfUpdaterService.prototype._shutdown =
  86. function gfUpdaterService__shutdown()
  87. {
  88.   d("shutdown");
  89.  
  90.   if (this._timer) {
  91.     this._timer.cancel();
  92.     this._timer = null;
  93.   }
  94. }
  95.  
  96. gfUpdaterService.prototype._updateNextUpdateDate =
  97. function gfUpdaterService__updateNextUpdateDate(aMinutes)
  98. {
  99.   var ms = aMinutes * MINUTE_IN_MS;
  100.   this._prefs.setCharPref("next_update_date", Date.now() + ms);
  101. }
  102.  
  103. gfUpdaterService.prototype._processDownload =
  104. function gfUpdaterService__processDownload()
  105. {
  106.   var zipReader = Cc["@mozilla.org/libjar/zip-reader;1"]
  107.                     .createInstance(Ci.nsIZipReader);
  108.  
  109.   var status = Cr.NS_OK;
  110.   var message = "OK";
  111.  
  112.   try {
  113.     zipReader.open(this._dest);
  114.     JARFILES.forEach(function(e) {
  115.       zipReader.test(e);
  116.     });
  117.  
  118.     // Create a temp dir for unpacking
  119.     var em = Cc["@mozilla.org/extensions/manager;1"]
  120.                .getService(Ci.nsIExtensionManager);
  121.     var installLocation = em.getInstallLocation("greasefire@skrul.com");
  122.     var exDir = installLocation.location;
  123.     exDir.append("greasefire@skrul.com");
  124.  
  125.     var unpackDir = exDir.clone();
  126.     unpackDir.append("indexes.new");
  127.     unpackDir.createUnique(Ci.nsIFile.DIRECTORY_TYPE, 0755);
  128.  
  129.     JARFILES.forEach(function(e) {
  130.       var f = unpackDir.clone();
  131.       f.append(e);
  132.       zipReader.extract(e, f);
  133.     });
  134.  
  135.     var oldIndexDir = exDir.clone();
  136.     oldIndexDir.append("indexes");
  137.  
  138.     var backupDir = exDir.clone();
  139.     backupDir.append("indexes.backup");
  140.     backupDir.createUnique(Ci.nsIFile.DIRECTORY_TYPE, 0755);
  141.  
  142.     // Stop the greasefire service and move the dirs around
  143.     this._gfs.shutdown();
  144.     try {
  145.       if (oldIndexDir.exists()) {
  146.         oldIndexDir.moveTo(backupDir, "");
  147.       }
  148.       unpackDir.moveTo(null, "indexes");
  149.       this._gfs.startup();
  150.     }
  151.     catch (e) {
  152.       // Something went wrong, move things back
  153.       Cu.reportError("Error moving indexes " + e.message);
  154.       status = Cr.NS_ERROR_FAILURE;
  155.       message = "Error moving indexes: " + e.message;
  156.  
  157.       unpackDir.remove(true);
  158.       oldIndexDir.moveTo(exDir, "");
  159.       this._gfs.startup();
  160.     }
  161.  
  162.     // Everything is ok, delete the backup dir
  163.     backupDir.remove(true);
  164.   }
  165.   catch (e) {
  166.     Cu.reportError(e);
  167.     if (status = Cr.NS_OK) {
  168.       status = Cr.NS_ERROR_FAILURE;
  169.       message = e.message;
  170.     }
  171.   }
  172.  
  173.   TRYIGNORE(function() {
  174.     zipReader.close();
  175.   });
  176.  
  177.   this._updateFinished(status, message);
  178. }
  179.  
  180. gfUpdaterService.prototype._updateFinished =
  181. function gfUpdaterService__updateFinished(aStatus, aMessage) {
  182.  
  183.   this._isUpdating = false;
  184.  
  185.   if (this._dest) {
  186.     var dest = this._dest;
  187.     TRYIGNORE(function() {
  188.       dest.remove(false);
  189.     });
  190.     this._dest = null;
  191.   }
  192.  
  193.   if (this._wbp) {
  194.     this._wbp.progressListener = null;
  195.   }
  196.   this._wbp = null;
  197.  
  198.   this._notify(function(l) {
  199.     l.onUpdateFinished(aStatus, aMessage);
  200.   });
  201. }
  202.  
  203. gfUpdaterService.prototype._notify =
  204. function gfUpdaterService__notify(aFunc)
  205. {
  206.   this._listeners.forEach(function(l) {
  207.     try {
  208.       aFunc(l);
  209.     }
  210.     catch (e) {
  211.       Cu.reportError(e);
  212.     }
  213.   });
  214. }
  215.  
  216. // gfIUpdaterService
  217. gfUpdaterService.prototype.startUpdate =
  218. function gfUpdaterService_startUpdate(aForce)
  219. {
  220.   if (this._isUpdating) {
  221.     return;
  222.   }
  223.  
  224.   this._isUpdating = true;
  225.   this._notify(function(l) {
  226.     l.onUpdateStarted();
  227.   });
  228.  
  229.   try {
  230.     this._wbp = Cc["@mozilla.org/embedding/browser/nsWebBrowserPersist;1"]
  231.                   .createInstance(Ci.nsIWebBrowserPersist);
  232.     this._wbp.progressListener = this;
  233.  
  234.     // Create a destination file for the download
  235.     this._dest = Cc["@mozilla.org/file/directory_service;1"]
  236.                  .getService(Ci.nsIProperties)
  237.                  .get("TmpD", Ci.nsIFile);
  238.     this._dest.append("greasefire_index_download.jar");
  239.     this._dest.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0666);
  240.  
  241.     // Start the download
  242.     var ios = Cc["@mozilla.org/network/io-service;1"]
  243.                 .getService(Ci.nsIIOService);
  244.     var uri = ios.newURI(UPDATE_URL, null, null);
  245.  
  246.     var headers = null;
  247.     if (this._gfs.indexDate > 0 && !aForce) {
  248.       headers = "If-Modified-Since: " +
  249.                 (new Date(this._gfs.indexDate)).toGMTString() + "\r\n";
  250.     }
  251.  
  252.     this._wbp.saveURI(uri, null, null, null, headers, this._dest);
  253.   }
  254.   catch (e) {
  255.     // Something went wrong setting up the download.
  256.     Cu.reportError(e);
  257.     this._updateFinished(Cr.NS_ERROR_FAILURE, e.message);
  258.   }
  259.  
  260. }
  261.  
  262. gfUpdaterService.prototype.cancelUpdate =
  263. function gfUpdaterService_cancelUpdate()
  264. {
  265.   if (this._isUpdating && this._wbp) {
  266.     this._wbp.cancelSave();
  267.   }
  268. }
  269.  
  270. gfUpdaterService.prototype.__defineGetter__("isUpdating",
  271. function gfUpdaterService_get_isUpdating()
  272. {
  273.   return this._isUpdating;
  274. });
  275.  
  276. gfUpdaterService.prototype.__defineGetter__("nextUpdateDate",
  277. function gfUpdaterService_get_nextUpdateDate()
  278. {
  279.   try {
  280.     return parseInt(this._prefs.getCharPref("next_update_date"));
  281.   }
  282.   catch(e) {
  283.   }
  284.   return 0;
  285. });
  286.  
  287. gfUpdaterService.prototype.__defineGetter__("updateIntervalMinutes",
  288. function gfUpdaterService_get_updateIntervalMinutes()
  289. {
  290.   try {
  291.     return this._prefs.getIntPref("update_interval_minutes");
  292.   }
  293.   catch(e) {
  294.   }
  295.   return 0;
  296. });
  297.  
  298. gfUpdaterService.prototype.__defineSetter__("updateIntervalMinutes",
  299. function gfUpdaterService_set_updateIntervalMinutes(aMinutes)
  300. {
  301.   this._prefs.setIntPref("update_interval_minutes", aMinutes);
  302.   this._updateNextUpdateDate(aMinutes);
  303. });
  304.  
  305. gfUpdaterService.prototype.addListener =
  306. function gfUpdaterService_addListener(aListener)
  307. {
  308.   if (this._listeners.indexOf(aListener) >= 0) {
  309.     return;
  310.   }
  311.   this._listeners.push(aListener);
  312. }
  313.  
  314. gfUpdaterService.prototype.removeListener =
  315. function gfUpdaterService_removeListener(aListener)
  316. {
  317.   this._listeners.filter(function(e) {
  318.     return aListener != e;
  319.   });
  320. }
  321.  
  322. // nsIWebProgressListener
  323. gfUpdaterService.prototype.onStateChange =
  324. function gfUpdaterService_onStateChange(aWebProgress,
  325.                                         aRequest,
  326.                                         aStateFlags,
  327.                                         aStatus)
  328. {
  329.   d("onStateChange");
  330.   if (this._isUpdating && aStateFlags & Ci.nsIWebProgressListener.STATE_STOP) {
  331.  
  332.     if (this._wbp.result == Cr.NS_BINDING_ABORTED) {
  333.       this._updateFinished(Cr.NS_BINDING_ABORTED, "Cancelled");
  334.       return;
  335.     }
  336.  
  337.     var responseStatus = null;
  338.     try {
  339.       responseStatus = aRequest.QueryInterface(Ci.nsIHttpChannel).responseStatus;
  340.     }
  341.     catch (e) {
  342.     }
  343.  
  344.     if (responseStatus == 200) {
  345.       this._processDownload();
  346.       return;
  347.     }
  348.  
  349.     if (responseStatus == 304) {
  350.       this._updateFinished(Cr.NS_ERROR_FILE_ALREADY_EXISTS, "Not Modified");
  351.       return;
  352.     }
  353.  
  354.     this._updateFinished(Cr.NS_ERROR_FAILURE,
  355.                          "status = 0x" + aStatus.toString(16) + " " +
  356.                          "http = " + responseStatus);
  357.   }
  358. }
  359.  
  360. gfUpdaterService.prototype.onProgressChange =
  361. function gfUpdaterService_onProgressChange(aWebProgress,
  362.                                            aRequest,
  363.                                            aCurSelfProgress,
  364.                                            aMaxSelfProgress,
  365.                                            aCurTotalProgress,
  366.                                            aMaxTotalProgress)
  367. {
  368.   if (this._isUpdating) {
  369.     this._notify(function(l) {
  370.       l.onDownloadProgress(aCurTotalProgress, aMaxTotalProgress);
  371.     });
  372.   }
  373. }
  374.  
  375. gfUpdaterService.prototype.onLocationChange =
  376. function gfUpdaterService_onLocationChange(aWebProgress, aRequest, aLocation)
  377. {
  378. }
  379.  
  380. gfUpdaterService.prototype.onStatusChange =
  381. function gfUpdaterService_onStatusChange(aWebProgress,
  382.                                          aRequest,
  383.                                          aStatus,
  384.                                          aMessage)
  385. {
  386. }
  387.  
  388. gfUpdaterService.prototype.onSecurityChange =
  389. function gfUpdaterService_onSecurityChange(aWebProgress, aRequest, aState)
  390. {
  391. }
  392.  
  393. // nsITimer
  394. gfUpdaterService.prototype.notify =
  395. function gfUpdaterService_notify(aTimer)
  396. {
  397.   if (this.updateIntervalMinutes > 0 && Date.now() > this.nextUpdateDate) {
  398.     this._updateNextUpdateDate(this.updateIntervalMinutes);
  399.     this.startUpdate(false);
  400.   }
  401. }
  402.  
  403. // nsIObserver
  404. gfUpdaterService.prototype.observe =
  405. function gfUpdaterService_observe(aSubject, aTopic, aData)
  406. {
  407.   if (aTopic == NS_PROFILE_STARTUP_OBSERVER_ID) {
  408.     this._startup();
  409.   }
  410.   else if (aTopic == NS_PROFILE_SHUTDOWN_OBSERVER_ID) {
  411.     this._shutdown();
  412.     var obs = Cc["@mozilla.org/observer-service;1"]
  413.                 .getService(Ci.nsIObserverService);
  414.     obs.removeObserver(this, NS_PROFILE_STARTUP_OBSERVER_ID);
  415.     obs.removeObserver(this, NS_PROFILE_SHUTDOWN_OBSERVER_ID);
  416.   }
  417. }
  418.  
  419. /*
  420.  * ***** BEGIN LICENSE BLOCK *****
  421.  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  422.  *
  423.  * The contents of this file are subject to the Mozilla Public License Version
  424.  * 1.1 (the "License"); you may not use this file except in compliance with
  425.  * the License. You may obtain a copy of the License at
  426.  * http://www.mozilla.org/MPL/
  427.  *
  428.  * Software distributed under the License is distributed on an "AS IS" basis,
  429.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  430.  * for the specific language governing rights and limitations under the
  431.  * License.
  432.  *
  433.  * The Original Code is Mozilla code.
  434.  *
  435.  * The Initial Developer of the Original Code is
  436.  * Netscape Communications Corporation.
  437.  * Portions created by the Initial Developer are Copyright (C) 2004
  438.  * the Initial Developer. All Rights Reserved.
  439.  *
  440.  * Contributor(s):
  441.  *    Alex Fritze <alex@croczilla.com> (original author)
  442.  *    Nickolay Ponomarev <asqueella@gmail.com>
  443.  *
  444.  * Alternatively, the contents of this file may be used under the terms of
  445.  * either the GNU General Public License Version 2 or later (the "GPL"), or
  446.  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  447.  * in which case the provisions of the GPL or the LGPL are applicable instead
  448.  * of those above. If you wish to allow use of your version of this file only
  449.  * under the terms of either the GPL or the LGPL, and not to allow others to
  450.  * use your version of this file under the terms of the MPL, indicate your
  451.  * decision by deleting the provisions above and replace them with the notice
  452.  * and other provisions required by the GPL or the LGPL. If you do not delete
  453.  * the provisions above, a recipient may use your version of this file under
  454.  * the terms of any one of the MPL, the GPL or the LGPL.
  455.  *
  456.  * ***** END LICENSE BLOCK ***** */
  457.  
  458. /**
  459.  * Utilities for JavaScript components loaded by the JS component
  460.  * loader.
  461.  *
  462.  * Import into a JS component using
  463.  * 'Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");'
  464.  *
  465.  * Exposing a JS 'class' as a component using these utility methods consists
  466.  * of several steps:
  467.  * 0. Import XPCOMUtils, as described above.
  468.  * 1. Declare the 'class' (or multiple classes) implementing the component(s):
  469.  *  function MyComponent() {
  470.  *    // constructor
  471.  *  }
  472.  *  MyComponent.prototype = {
  473.  *    // properties required for XPCOM registration:
  474.  *    classDescription: "unique text description",
  475.  *    classID:          Components.ID("{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}"),
  476.  *    contractID:       "@example.com/xxx;1",
  477.  *
  478.  *    // [optional] custom factory (an object implementing nsIFactory). If not
  479.  *    // provided, the default factory is used, which returns
  480.  *    // |(new MyComponent()).QueryInterface(iid)| in its createInstance().
  481.  *    _xpcom_factory: { ... },
  482.  *
  483.  *    // [optional] an array of categories to register this component in.
  484.  *    _xpcom_categories: [{
  485.  *      // Each object in the array specifies the parameters to pass to
  486.  *      // nsICategoryManager.addCategoryEntry(). 'true' is passed for
  487.  *      // both aPersist and aReplace params.
  488.  *      category: "some-category",
  489.  *      // optional, defaults to the object's classDescription
  490.  *      entry: "entry name",
  491.  *      // optional, defaults to the object's contractID (unless
  492.  *      // 'service' is specified)
  493.  *      value: "...",
  494.  *      // optional, defaults to false. When set to true, and only if 'value'
  495.  *      // is not specified, the concatenation of the string "service," and the
  496.  *      // object's contractID is passed as aValue parameter of addCategoryEntry.
  497.  *      service: true
  498.  *    }],
  499.  *
  500.  *    // QueryInterface implementation, e.g. using the generateQI helper
  501.  *    QueryInterface: XPCOMUtils.generateQI(
  502.  *      [Components.interfaces.nsIObserver,
  503.  *       Components.interfaces.nsIMyInterface]),
  504.  *
  505.  *    // ...component implementation...
  506.  *  };
  507.  *
  508.  * 2. Create an array of component constructors (like the one
  509.  * created in step 1):
  510.  *  var components = [MyComponent];
  511.  *
  512.  * 3. Define the NSGetModule entry point:
  513.  *  function NSGetModule(compMgr, fileSpec) {
  514.  *    // components is the array created in step 2.
  515.  *    return XPCOMUtils.generateModule(components);
  516.  *  }
  517.  */
  518.  
  519. var XPCOMUtils = {
  520.   /**
  521.    * Generate a QueryInterface implementation. The returned function must be
  522.    * assigned to the 'QueryInterface' property of a JS object. When invoked on
  523.    * that object, it checks if the given iid is listed in the |interfaces|
  524.    * param, and if it is, returns |this| (the object it was called on).
  525.    */
  526.   generateQI: function(interfaces) {
  527.     return makeQI([i.name for each(i in interfaces)]);
  528.   },
  529.  
  530.   /**
  531.    * Generate the NSGetModule function (along with the module definition).
  532.    * See the parameters to generateModule.
  533.    */
  534.   generateNSGetModule: function(componentsArray, postRegister, preUnregister) {
  535.     return function NSGetModule(compMgr, fileSpec) {
  536.       return XPCOMUtils.generateModule(componentsArray,
  537.                                        postRegister,
  538.                                        preUnregister);
  539.     }
  540.   },
  541.  
  542.   /**
  543.    * Generate a module implementation.
  544.    *
  545.    * @param componentsArray  Array of component constructors. See the comment
  546.    *                         at the top of this file for details.
  547.    * @param postRegister  optional post-registration function with
  548.    *                      signature 'postRegister(nsIComponentManager,
  549.    *                                              nsIFile, componentsArray)'
  550.    * @param preUnregister optional pre-unregistration function with
  551.    *                      signature 'preUnregister(nsIComponentManager,
  552.    *                                               nsIFile, componentsArray)'
  553.    */
  554.   generateModule: function(componentsArray, postRegister, preUnregister) {
  555.     let classes = [];
  556.     for each (let component in componentsArray) {
  557.       classes.push({
  558.         cid:          component.prototype.classID,
  559.         className:    component.prototype.classDescription,
  560.         contractID:   component.prototype.contractID,
  561.         factory:      this._getFactory(component),
  562.         categories:   component.prototype._xpcom_categories
  563.       });
  564.     }
  565.  
  566.     return { // nsIModule impl.
  567.       getClassObject: function(compMgr, cid, iid) {
  568.         // We only support nsIFactory queries, not nsIClassInfo
  569.         if (!iid.equals(Ci.nsIFactory))
  570.           throw Cr.NS_ERROR_NOT_IMPLEMENTED;
  571.  
  572.         for each (let classDesc in classes) {
  573.           if (classDesc.cid.equals(cid))
  574.             return classDesc.factory;
  575.         }
  576.  
  577.         throw Cr.NS_ERROR_FACTORY_NOT_REGISTERED;
  578.       },
  579.  
  580.       registerSelf: function(compMgr, fileSpec, location, type) {
  581.         var componentCount = 0;
  582.         debug("*** registering " + fileSpec.leafName + ": [ ");
  583.         compMgr.QueryInterface(Ci.nsIComponentRegistrar);
  584.  
  585.         for each (let classDesc in classes) {
  586.           debug((componentCount++ ? ", " : "") + classDesc.className);
  587.           compMgr.registerFactoryLocation(classDesc.cid,
  588.                                           classDesc.className,
  589.                                           classDesc.contractID,
  590.                                           fileSpec,
  591.                                           location,
  592.                                           type);
  593.           if (classDesc.categories) {
  594.             let catMan = XPCOMUtils.categoryManager;
  595.             for each (let cat in classDesc.categories) {
  596.               let defaultValue = (cat.service ? "service," : "") +
  597.                                  classDesc.contractID;
  598.               catMan.addCategoryEntry(cat.category,
  599.                                       cat.entry || classDesc.className,
  600.                                       cat.value || defaultValue,
  601.                                       true, true);
  602.             }
  603.           }
  604.         }
  605.  
  606.         if (postRegister)
  607.           postRegister(compMgr, fileSpec, componentsArray);
  608.         debug(" ]\n");
  609.       },
  610.  
  611.       unregisterSelf: function(compMgr, fileSpec, location) {
  612.         var componentCount = 0;
  613.         debug("*** unregistering " + fileSpec.leafName + ": [ ");
  614.         compMgr.QueryInterface(Ci.nsIComponentRegistrar);
  615.         if (preUnregister)
  616.           preUnregister(compMgr, fileSpec, componentsArray);
  617.  
  618.         for each (let classDesc in classes) {
  619.           debug((componentCount++ ? ", " : "") + classDesc.className);
  620.           if (classDesc.categories) {
  621.             let catMan = XPCOMUtils.categoryManager;
  622.             for each (let cat in classDesc.categories) {
  623.               catMan.deleteCategoryEntry(cat.category,
  624.                                          cat.entry || classDesc.className,
  625.                                          true);
  626.             }
  627.           }
  628.           compMgr.unregisterFactoryLocation(classDesc.cid, fileSpec);
  629.         }
  630.         debug(" ]\n");
  631.       },
  632.  
  633.       canUnload: function(compMgr) {
  634.         return true;
  635.       }
  636.     };
  637.   },
  638.  
  639.   /**
  640.    * Convenience access to category manager
  641.    */
  642.   get categoryManager() {
  643.     return Components.classes["@mozilla.org/categorymanager;1"]
  644.            .getService(Ci.nsICategoryManager);
  645.   },
  646.  
  647.   /**
  648.    * Returns an nsIFactory for |component|.
  649.    */
  650.   _getFactory: function(component) {
  651.     var factory = component.prototype._xpcom_factory;
  652.     if (!factory) {
  653.       factory = {
  654.         createInstance: function(outer, iid) {
  655.           if (outer)
  656.             throw Cr.NS_ERROR_NO_AGGREGATION;
  657.           return (new component()).QueryInterface(iid);
  658.         }
  659.       }
  660.     }
  661.     return factory;
  662.   }
  663. };
  664.  
  665. /**
  666.  * Helper for XPCOMUtils.generateQI to avoid leaks - see bug 381651#c1
  667.  */
  668. function makeQI(interfaceNames) {
  669.   return function XPCOMUtils_QueryInterface(iid) {
  670.     if (iid.equals(Ci.nsISupports))
  671.       return this;
  672.     for each(let interfaceName in interfaceNames) {
  673.       if (Ci[interfaceName].equals(iid))
  674.         return this;
  675.     }
  676.  
  677.     throw Cr.NS_ERROR_NO_INTERFACE;
  678.   };
  679. }
  680.  
  681. //@line 420 "/home/steve/dev/mozilla/1.8/mozilla/extensions/greasefire/src/gfUpdaterService.js"
  682.  
  683. gfUpdaterService.prototype.QueryInterface =
  684.   XPCOMUtils.generateQI([Ci.gfIUpdaterService,
  685.                          Ci.nsIObserver,
  686.                          Ci.nsIWebProgressListener,
  687.                          Ci.nsITimerCallback]);
  688.  
  689. var NSGetModule = XPCOMUtils.generateNSGetModule(
  690.   [
  691.     gfUpdaterService
  692.   ],
  693.   function(aCompMgr, aFileSpec, aLocation) {
  694.     XPCOMUtils.categoryManager.addCategoryEntry(
  695.       "app-startup",
  696.       gfUpdaterService.prototype.classDescription,
  697.       "service," + gfUpdaterService.prototype.contractID,
  698.       true,
  699.       true);
  700.   }
  701. );
  702.  
  703. function do(o) {
  704.  
  705.   var s = "";
  706.   if (typeof(o) == "string") {
  707.     s = o;
  708.   }
  709.   else {
  710.     if (o.length) {
  711.     }
  712.     else {
  713.       var a = [];
  714.       for (var k in o) {
  715.         a.push(k + " => " + o[k]);
  716.       }
  717.       s = a.join(", ");
  718.     }
  719.   }
  720.  
  721.   dump("[updater]  " + s + "\n");
  722.  
  723. }
  724.